using System;
using ValidationFramework;
using ValidationFramework.Configuration;
using ValidationFramework.Reflection;

namespace ExampleLibraryCSharp.NewRule
{
    public class RequiredCharacterRule : ValueRule
    {
        #region Fields

        // RequiredCharacterRule can only be applied to strings. So pass the 
        // <see cref="RuntimeTypeHandle"/> for string to the base constructor.
		private static readonly RuntimeTypeHandle runtimeTypeHandle = TypePointers.StringTypeHandle;
        //the required character

        #endregion


        #region Constructors

        /// <summary>
        /// Initialize a new instance of the <see cref="RequiredCharacterRule"/> class.
        /// </summary>
        /// <remarks>To help with cloning.</remarks>
        private RequiredCharacterRule():base(runtimeTypeHandle)
        {
            
        }
        /// <summary>
        /// Initialize a new instance of the <see cref="RequiredCharacterRule"/> class.
        /// </summary>
        /// <param name="errorMessage">The custom error message to use. Pass a null to 
        /// use the default value.</param>
        /// <param name="requiredCharacter">The invalid character.</param>
        /// <param name="useErrorMessageProvider"><c>true</c> to use 
        /// <see cref="ConfigurationService.ErrorMessageProvider"/> when determining the 
        /// error message for this <see cref="Rule"/>; otherwise <c>false</c>.</param>
        public RequiredCharacterRule(string errorMessage, bool useErrorMessageProvider, char requiredCharacter)
            : base(runtimeTypeHandle)
        {
            RequiredCharacter = requiredCharacter;
        }

        #endregion


        #region Properties

        /// <summary>
        /// Gets the required character.
        /// </summary>
        public char RequiredCharacter { get; private set; }

        /// <summary>
        /// Gets a <see cref="string"/> that is a business interpretation of the 
        /// <see cref="Rule"/>.
        /// </summary>
        public override string RuleInterpretation
        {
            get
            {
                return string.Format("The value must contain the character '{0}'", 
                    RequiredCharacter);
            }
        }


        #endregion


        #region Methods

        /// <summary>
        /// Called after <see cref="InfoDescriptor"/> is set but only when <see cref="Rule.ErrorMessage"/> is null.
        /// </summary>
        /// <remarks>
        /// Used by inheritors to provide a customized default <see cref="Rule.ErrorMessage"/>.
        /// </remarks>
        /// <returns>The error message for the <see cref="Rule"/>.</returns>
        /// <param name="tokenizedMemberName">A user friendly representation of the member name.</param>
        /// <param name="descriptorType">
        /// If <see cref="InfoDescriptor"/> is a <see cref="PropertyDescriptor"/> then <paramref name="descriptorType"/> will be 'property'.
        /// If <see cref="InfoDescriptor"/> is a <see cref="ParameterDescriptor"/> then <paramref name="descriptorType"/> will be 'parameter'.
        /// </param>
        protected override string GetComputedErrorMessage(string tokenizedMemberName, string descriptorType)
        {
            return string.Format("The {0} '{1}' must contain the character '{2}'",
             descriptorType, tokenizedMemberName, RequiredCharacter);
        }


        /// <summary>
        /// Validate the member this <see cref="Rule"/> is applied to.
        /// </summary>
        /// <param name="context">An <see cref="object"/> that contains data for the 
        /// <see cref="Rule"/> to validate. The default is null.</param>
        /// <param name="targetMemberValue">The value of the member to validate.</param>
        public override bool Validate(object targetMemberValue, object context, InfoDescriptor infoDescriptor)
        {
            if (targetMemberValue != null)
            {
                var valueAsString = (string)targetMemberValue;
                return (valueAsString.IndexOf(RequiredCharacter) != -1);
            }
            return true;
        }


        /// <summary>
        /// Checks if the current <see cref="Rule"/> is equivalent to another 
        /// <see cref="Rule"/>.
        /// </summary>
        /// <remarks>
        /// Called for each <see cref="Rule"/> in <see cref="RuleCollection"/> when a new 
        /// <see cref="Rule"/> is added. This method is only called when both the existing 
        /// <see cref="Rule"/> and the <see cref="Rule"/> being are of the same 
        /// <see cref="Type"/> and have the same RuleSet. So it is safe
        ///  to directly cast <paramref name="rule"/> to the current type. All properties 
        /// in <paramref name="rule"/> should be compared to the propeties of the current 
        /// <see cref="Rule"/>.
        /// </remarks>
        /// <param name="rule">The <see cref="Rule"/> to check for equivalence.</param>
        /// <returns><see langword="true"/> if <paramref name="rule"/> is equivalent to 
        /// the current <see cref="Rule"/>; otherwise <see langword="false"/>.</returns>
        public override bool IsEquivalent(Rule rule)
        {
            var requiredCharacterRule = (RequiredCharacterRule)rule;
            return RequiredCharacter == requiredCharacterRule.RequiredCharacter;
        }



        #endregion


    }
}